#include "bsp_usart.h"
#include <stdint.h>
#include <stdio.h>

#pragma import(__use_no_semihosting)
struct __FILE {
    int handle;
};
FILE __stdout;
void _sys_exit(int x) // 定义_sys_exit()以避免使用半主机模式
{
    x = x;
}
// int fputc(int ch, FILE *f) // 重定义fputc函数
//{
//     // 查询USART2状态寄存器，等待TXE标志置位表示数据发送寄存器空
//     if (USART2->SR & 0x40)  // 检查是否可以发送数据
//     {
//         USART2->DR = (uint8_t)ch;  // 发送数据
//         return ch;
//     }
//
//     return -1; // 返回-1表示发送失败
// }

// 定义缓冲区大小
#define BUFFER_SIZE 1000

// 全局缓冲区和指针
static uint8_t tx_buffer[BUFFER_SIZE];
static uint16_t tx_head = 0;
static uint16_t tx_tail = 0;

// 串口发送函数
int fputc(int ch, FILE *f)
{
    // 确保缓冲区有足够空间来存储数据
    uint16_t next_head = (tx_head + 1) % BUFFER_SIZE;

    // 如果缓冲区满了，返回EOF表示失败
    if (next_head == tx_tail) {
        return EOF;
    }

    // 将字符放入缓冲区
    tx_buffer[tx_head] = (uint8_t)ch;
    tx_head            = next_head;

    // 尝试发送数据（仅当发送寄存器空时）
    if (USART2->SR & USART_SR_TXE) // TXE标志置位，表示发送寄存器空
    {
        USART2->DR = tx_buffer[tx_tail];
        tx_tail    = (tx_tail + 1) % BUFFER_SIZE;
    }

    return ch;
}

// 需要周期性地调用这个函数来处理缓冲区中的数据
void process_tx_buffer(void)
{
    // 如果发送寄存器空，并且缓冲区中有数据
    if (USART2->SR & USART_SR_TXE && tx_tail != tx_head) {
        USART2->DR = tx_buffer[tx_tail];          // 发送缓冲区中的字符
        tx_tail    = (tx_tail + 1) % BUFFER_SIZE; // 更新缓冲区尾部
    }
}
/**
 * @brief 发送单个字符函数
 * @param pUSARTx 串口编号 USART2
 * @param ch 要发送的单个字符
 */
void Usart_SendByte(USART_TypeDef *pUSARTx, uint8_t ch)
{
    /* 发送一个字节数据到USART */
    USART_SendData(pUSARTx, ch);
    /* 等待发送数据寄存器为空 */
    while (USART_GetFlagStatus(pUSARTx, USART_FLAG_TXE) == RESET);
}
/**
 * @brief 发送字符串函数
 * @param pUSARTx 串口编号 USART2
 * @param str 要发送的一整个字符串
 */
void Usart_SendString(USART_TypeDef *pUSARTx, char *str)
{
    unsigned int k = 0;
    do {
        Usart_SendByte(pUSARTx, *(str + k));
        k++;
    } while (*(str + k) != '\0');
    /* 等待发送完成 */
    while (USART_GetFlagStatus(pUSARTx, USART_FLAG_TC) == RESET);
}

// 串口收发颜色传感器
void USART2_Init(void)
{
    // GPIO端口设置
    GPIO_InitTypeDef GPIO_InitStructure;
    USART_InitTypeDef USART_InitStructure;
    NVIC_InitTypeDef NVIC_InitStructure;

    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOD, ENABLE);  // 使能GPIOB时钟
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE); // 使能USART2时钟

    // 串口2对应引脚复用映射
    GPIO_PinAFConfig(GPIOD, GPIO_PinSource5, GPIO_AF_USART2); // GPIOD5复用为USART2 TX
    GPIO_PinAFConfig(GPIOD, GPIO_PinSource6, GPIO_AF_USART2); // GPIOD6复用为USART2 RX

    // USART2端口配置
    /* PD5用于TX数据输出, PD6用于RX数据输入 */
    GPIO_InitStructure.GPIO_Pin   = GPIO_Pin_5 | GPIO_Pin_6; // 复用推挽输出
    GPIO_InitStructure.GPIO_Mode  = GPIO_Mode_AF;            // 复用功能
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;       // 速度100MHz
    GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;           // 推挽复用输出
    GPIO_InitStructure.GPIO_PuPd  = GPIO_PuPd_UP;            // 上拉
    GPIO_Init(GPIOD, &GPIO_InitStructure);                   // 初始化
    // USART2 初始化设置
    USART_InitStructure.USART_BaudRate            = 9600;                           // 波特率设置
    USART_InitStructure.USART_WordLength          = USART_WordLength_8b;            // 字长为8位数据格式
    USART_InitStructure.USART_StopBits            = USART_StopBits_1;               // 一个停止位
    USART_InitStructure.USART_Parity              = USART_Parity_No;                // 无奇偶校验位
    USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None; // 无硬件数据流控制
    USART_InitStructure.USART_Mode                = USART_Mode_Rx | USART_Mode_Tx;  // 收发模式
    USART_Init(USART2, &USART_InitStructure);                                       // 初始化串口2

    USART_Cmd(USART2, ENABLE); // 使能串口2

    // Usart2 NVIC 配置
    USART_ITConfig(USART2, USART_IT_RXNE, DISABLE); // 开启接收中断

    NVIC_InitStructure.NVIC_IRQChannel                   = USART2_IRQn; // 串口3中断通道
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 3;           // 抢占优先级3
    NVIC_InitStructure.NVIC_IRQChannelSubPriority        = 3;           // 子优先级1

    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; // IRQ通道使能
    NVIC_Init(&NVIC_InitStructure);                 // 根据指定的参数初始化NVIC寄存器
}

void USART2_IRQHandler(void) // 串口2中断服务程序
{
    static uint8_t USART_RX_BUF[USART_REC_LEN]; // 接收缓冲,最大USART_REC_LEN个字节.
    uint8_t Res;
    uint8_t len;
    uint8_t t;
    static uint16_t USART_RX_STA = 0; // 接收状态标记
    if (USART_GetITStatus(USART2, USART_IT_RXNE) != RESET) {
        Res = USART_ReceiveData(USART2);  //(USART2->DR);	//读取接收到的数据
        if ((USART_RX_STA & 0x8000) == 0) // 接收未完成
        {
            if (USART_RX_STA & 0x4000) // 接收到了0x0D
            {
                if (Res != 0x0a)
                    USART_RX_STA = 0; // 接收错误,重新开始
                else
                    USART_RX_STA |= 0x8000; // 接收完成了
            } else                          // 还没收到0X0D
            {
                if (Res == 0x0d)
                    USART_RX_STA |= 0x4000;
                else {
                    USART_RX_BUF[USART_RX_STA & 0X3FFF] = Res;
                    USART_RX_STA++;
                    if (USART_RX_STA > (USART_REC_LEN - 1)) USART_RX_STA = 0; // 接收数据错误,重新开始接收
                }
            }
        }
    }
    // 接收完成, 将接收到的数据原路发送回去
    if (USART_RX_STA & 0x8000) {
        len               = USART_RX_STA & 0xfff;
        USART_RX_STA      = 0;    // 接收指数归零
        USART_RX_BUF[len] = 0;    // 接收缓存区后面清零
        for (t = 0; t < len; t++) // 原路回传
        {
            USART_SendData(USART2, USART_RX_BUF[t]);                   // 向串口1回传数据
            while (USART_GetFlagStatus(USART2, USART_FLAG_TC) != SET); // 等待发送结束
        }
    }
}
